"""
数据库模块 - 基础服务 (BaseService)

提供业务逻辑层的基类，它通过组合一个 Mapper 实例，为子类提供开箱即用的数据访问能力。
"""
from __future__ import annotations
import abc
from typing import Any, Dict, Generic, List, Optional, Tuple, TypeVar, Union

from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession

from axiom_boot.database.base_mapper import BaseMapper
from axiom_boot.database.base_model import BaseModel
from axiom_boot.api.models import PaginationParams, FilterParams, PaginatedResponse
from axiom_boot.core.exceptions import BusinessException, NotFoundException
from axiom_boot.di import autowired
from axiom_boot.core.id_generator import IdGenerator


T = TypeVar("T", bound=BaseModel)
M = TypeVar("M", bound=BaseMapper)


class BaseService(Generic[T, M], metaclass=abc.ABCMeta):
    """
    一个通用的、异步的业务服务基类。

    它通过 @autowired 字段注入来自动获取通用的数据库依赖，
    并通过构造函数注入来获取其具体的 Mapper 实例。
    """
    db_session_factory: async_sessionmaker[AsyncSession] = autowired("async_sessionmaker")
    id_generator: IdGenerator = autowired()

    def __init__(self, mapper: M):
        """
        初始化基础服务。

        参数:
            mapper: 一个具体的、已经被DI容器注入了依赖的 Mapper 实例。
        """
        self.mapper = mapper

    async def find_by_pk_or_fail(self, pk: Union[int, str], include_deleted: bool = False) -> T:
        """根据主键异步查询单个记录，如果未找到则抛出 NotFoundException"""
        model = await self.mapper.find_by_pk(pk, include_deleted)
        if model is None:
            raise NotFoundException(f"ID 为 {pk} 的资源不存在")
        return model

    async def update_by_pk(self, pk: Union[int, str], values: Dict[str, Any]) -> T:
        """
        根据主键异步更新记录。
        如果记录不存在，则抛出 NotFoundException。
        """
        updated_model = await self.mapper.update_by_pk(pk, values)
        if updated_model is None:
            raise NotFoundException(f"更新失败：ID 为 {pk} 的资源不存在")
        return updated_model

    async def delete_by_pk(self, pk: Union[int, str], hard_delete: bool = False):
        """
        根据主键删除记录（支持软删除和物理删除）。
        如果记录不存在，则抛出 NotFoundException。
        """
        success = await self.mapper.delete_by_pk(pk, hard_delete)
        if not success:
            raise NotFoundException(f"删除失败：ID 为 {pk} 的资源不存在")

    def __getattr__(self, name: str) -> Any:
        """
        魔术方法，用于将 Service 层未定义的方法调用透明地转发给底层的 Mapper 对象。
        这大大减少了 Service 基类中的冗余代码，并提高了框架的可扩展性。
        """
        # 从 self.mapper 中获取同名属性（方法）
        mapper_attr = getattr(self.mapper, name)
        
        # 确保我们只转发可调用的方法，以避免意外暴露其他属性
        if callable(mapper_attr):
            return mapper_attr
        
        # 如果不是可调用对象，则按正常行为抛出 AttributeError
        raise AttributeError(f"'{self.__class__.__name__}' object and its mapper have no attribute '{name}'") 